﻿using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;

namespace System.Data.SQL.Linq
{
    #region IOrderedQueryable<T>
    public sealed partial class DataQuery<T> : IOrderedQueryable<T>
    {
        public Type ElementType { get { return typeof(T); } }
        public Expression Expression { get; private set; }
        public IQueryProvider Provider { get { return this; } }
    }
    #endregion

    #region IQueryProvider
    public sealed partial class DataQuery<T> : IQueryProvider
    {
        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            if (expression == null) throw new ArgumentNullException();
            if (!typeof(IQueryable<TElement>).IsAssignableFrom(expression.Type)) throw new ArgumentException();
            return new DataQuery<TElement>(Context, expression);
        }
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
        public IQueryable CreateQuery(Expression expression)
        {
            if (expression == null) throw new ArgumentNullException();
            Type eType = TypeSystem.GetElementType(expression.Type);
            Type qType = typeof(IQueryable<>).MakeGenericType(eType);
            if (!qType.IsAssignableFrom(expression.Type)) throw new ArgumentException();
            Type dqType = typeof(DataQuery<>).MakeGenericType(eType);
            return (IQueryable)Activator.CreateInstance(dqType, new object[] { Context, expression });
        }

        public TResult Execute<TResult>(Expression expression)
        {
            return (TResult)Context.Provider.Execute(Expression).ReturnValue;
        }

        public object Execute(Expression expression)
        {
            return Context.Provider.Execute(Expression).ReturnValue;
        }
    }
    #endregion

    #region IEnumerable<T>
    public sealed partial class DataQuery<T> : IEnumerable<T>
    {
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return ((IEnumerable<T>)Context.Provider.Execute(Expression).ReturnValue).GetEnumerator();
        }
    }
    #endregion

    #region IEnumerable
    public sealed partial class DataQuery<T> : IEnumerable
    {
        public IEnumerator GetEnumerator()
        {
            return ((IEnumerable)Context.Provider.Execute(Expression).ReturnValue).GetEnumerator();
        }
    }
    #endregion

    #region IListSource
    public sealed partial class DataQuery<T> : IListSource
    {
        public bool ContainsListCollection
        {
            get { return false; }
        }

        public IList GetList()
        {
            throw new NotImplementedException();
        }
    }
    #endregion

    #region DataQuery<T>
    public sealed partial class DataQuery<T>
    {
        public DataContext Context { get; private set; }

        public DataQuery(DataContext context, Expression expression)
        {
            Context = context;
            Expression = expression;
        }
    }
    #endregion
}